home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cmdline.lha / cmdline / src / lib / usage.c < prev   
Encoding:
C/C++ Source or Header  |  1993-04-13  |  9.1 KB  |  325 lines

  1. //------------------------------------------------------------------------
  2. // ^FILE: usage.c - functions to print the usage of a CmdLine
  3. //
  4. // ^DESCRIPTION:
  5. //     This file contains the functions that are used to print the
  6. //  command-line usage of a command that is represented by a CmdLine
  7. //  object.
  8. //
  9. // ^HISTORY:
  10. //    01/09/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  11. //
  12. //    03/01/93    Brad Appleton    <brad@ssd.csd.harris.com>
  13. //    - Added cmd_description field to CmdLine
  14. //-^^---------------------------------------------------------------------
  15.  
  16. #include <iostream.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19.  
  20. #include "cmdline.h"
  21. #include "states.h"
  22. #include "arglist.h"
  23.  
  24. #ifdef vms
  25. #  define  getenv  getsym
  26.    extern  const char * getsym(const char *);
  27. #endif
  28.  
  29.  
  30. //-------
  31. // ^FUNCTION: CmdLine::get_usage_level
  32. //
  33. // ^SYNOPSIS:
  34. //    CmdLine::CmdUsageLevel CmdLine::get_usage_level(void)
  35. //
  36. // ^PARAMETERS:
  37. //    NONE.
  38. //
  39. // ^DESCRIPTION:
  40. //    Gets the usage_level that tells us how "verbose" we should be
  41. //    when printing usage-messages. This usage_level is recorded in
  42. //    the environment variable $USAGE_LEVEL. This variable may have the
  43. //    following values:
  44. //
  45. //       0 : Dont print usage at all.
  46. //       1 : Print a terse usage message (command-line syntax only).
  47. //       2 : Print a verbose usage message (include argument descriptions).
  48. //
  49. //    If $USAGE_LEVEL is not defined or is empty, then the default
  50. //    usage_level is 2.
  51. //
  52. // ^REQUIREMENTS:
  53. //
  54. // ^SIDE-EFFECTS:
  55. //    None.
  56. //
  57. // ^RETURN-VALUE:
  58. //    The usage level to use.
  59. //
  60. // ^ALGORITHM:
  61. //    Read the usage_level from the environment and return it.
  62. //-^^----
  63. CmdLine::CmdUsageLevel
  64. CmdLine::get_usage_level(void)
  65. {
  66.    long level;
  67.    char * end_scan, * level_str = ::getenv("USAGE_LEVEL");
  68.  
  69.    if (level_str == NULL)  return  VERBOSE_USAGE ;
  70.    if (*level_str == '\0') return  NO_USAGE ;
  71.  
  72.    level = ::strtol(level_str, &end_scan, 0);
  73.    if (end_scan == level_str)  return  VERBOSE_USAGE ;
  74.  
  75.    switch(level) {
  76.       case 0 :  return NO_USAGE ;
  77.       case 1 :  return TERSE_USAGE ;
  78.       default:  return VERBOSE_USAGE ;
  79.    }
  80. }
  81.  
  82. //-------
  83. // ^FUNCTION: CmdLine::print_synopsis
  84. //
  85. // ^SYNOPSIS:
  86. //    unsigned CmdLine::print_synopsis(syntax, os, cols)
  87. //
  88. // ^PARAMETERS:
  89. //    CmdLine::CmdLineSyntax syntax;
  90. //    -- the syntax to use (long-option, short-option, or both)
  91. //       when printing the synopsis.
  92. //
  93. //    ostream & os;
  94. //    -- where to print.
  95. //
  96. //    int cols;
  97. //    -- the maximum width of a line.
  98. //
  99. // ^DESCRIPTION:
  100. //    Print a command-line synopsis (the command-line syntax).
  101. //    The synopsis should be printed to "os" using the desired syntax,
  102. //    in lines that are no more than "cols" characters wide.
  103. //
  104. // ^REQUIREMENTS:
  105. //
  106. // ^SIDE-EFFECTS:
  107. //     Prints on "os".
  108. //
  109. // ^RETURN-VALUE:
  110. //     The length of the longest argument-buf that was printed.
  111. //
  112. // ^ALGORITHM:
  113. //     It's kind of complicated so follow along!
  114. //-^^----
  115. unsigned
  116. CmdLine::print_synopsis(CmdLine::CmdLineSyntax  syntax,
  117.                         ostream    & os,
  118.                         int          cols) const
  119. {
  120. #ifdef vms_style
  121.    static  char  usg_prefix[] = "Format: ";
  122. #else
  123.    static  char  usg_prefix[] = "Usage: ";
  124. #endif
  125.  
  126.    unsigned  ll, positionals, longest = 0;
  127.  
  128.    // first print the command name
  129.    os << usg_prefix << cmd_name ;
  130.    ll = (cmd_name ? ::strlen(cmd_name) : 0) + (sizeof(usg_prefix) - 1);
  131.  
  132.    // set margin so that we always start printing arguments in a column
  133.    // that is *past* the command name.
  134.    //
  135.    unsigned  margin = ll + 1;
  136.  
  137.    // print option-syntax followed by positional parameters
  138.    int  first;
  139.    char buf[256] ;
  140.    for (positionals = 0 ; positionals < 2 ; positionals++) {
  141.       first = 1;
  142.       CmdArgListListIter  list_iter(cmd_args);
  143.       for (CmdArgList * alist = list_iter() ; alist ; alist = list_iter()) {
  144.          CmdArgListIter  iter(alist);
  145.          for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  146.             unsigned  len, pl;
  147.  
  148.                // don't display hidden arguments
  149.             if (cmdarg->syntax() & CmdArg::isHIDDEN)  continue;
  150.             if (!positionals  &&  (cmdarg->syntax() & CmdArg::isPOS))  continue;
  151.             if (positionals  &&  !(cmdarg->syntax() & CmdArg::isPOS))  continue;
  152.  
  153.                // figure out how wide this parameter is (for printing)
  154.             pl = len = fmt_arg(cmdarg, buf, sizeof(buf), syntax, VERBOSE_USAGE);
  155.             if (! len)  continue;
  156.  
  157.             if (cmdarg->syntax() & CmdArg::isLIST)  pl -= 4 ;  // " ..."
  158.             if (! (cmdarg->syntax() & CmdArg::isREQ))  pl -= 2 ;   // "[]"
  159.             if (pl > longest)  longest = pl;
  160.  
  161.             //  Will this fit?
  162.             if ((ll + len + 1) > (cols - first)) {
  163.                os << char('\n') ;
  164.                os.width(margin);
  165.                os << "" ;  // No - start a new line;
  166.                ll = margin;
  167.             } else {
  168.                os << char(' ') ;  // Yes - just throw in a space
  169.                ++ll;
  170.             }
  171.             ll += len;
  172.             os << buf;
  173.  
  174.             first = 0;
  175.          } //for each cmdarg
  176.       } //for each arg-list
  177.    } //for each parm-type
  178.    os << endl ;
  179.  
  180.    return  longest ;
  181. }
  182.  
  183.  
  184. //-------
  185. // ^FUNCTION: CmdLine::print_descriptions
  186. //
  187. // ^SYNOPSIS:
  188. //    unsigned CmdLine::print_descriptions(syntax, os, cols, longest)
  189. //
  190. // ^PARAMETERS:
  191. //    CmdLine::CmdLineSyntax syntax;
  192. //    -- the syntax to use (long-option, short-option, or both)
  193. //       when printing the synopsis.
  194. //
  195. //    ostream & os;
  196. //    -- where to print.
  197. //
  198. //    int cols;
  199. //    -- the maximum width of a line.
  200. //
  201. //    unsigned longest;
  202. //    -- value returned by print_synopsis.
  203. //
  204. // ^DESCRIPTION:
  205. //    Print a command argument descriptions (using the command-line syntax).
  206. //    The descriptions should be printed to "os" using the desired syntax,
  207. //    in lines that are no more than "cols" characters wide.
  208. //
  209. // ^REQUIREMENTS:
  210. //    "longest" should correspond to a value returned by print_synopsis
  211. //    that used the same "cmd" and syntax.
  212. //
  213. // ^SIDE-EFFECTS:
  214. //     Prints on "os".
  215. //
  216. // ^RETURN-VALUE:
  217. //     None.
  218. //
  219. // ^ALGORITHM:
  220. //     Print the description for each argument.
  221. //-^^----
  222. void
  223. CmdLine::print_descriptions(CmdLine::CmdLineSyntax   syntax,
  224.                             ostream                & os,
  225.                             int                      cols,
  226.                             unsigned                 longest) const
  227. {
  228.    int positionals, options = 0;
  229.    char buf[256];
  230.  
  231.    for (positionals = 0 ; positionals < 2 ; positionals++) {
  232.       CmdArgListListIter  list_iter(cmd_args);
  233.       for (CmdArgList * alist = list_iter() ; alist ; alist = list_iter()) {
  234.          CmdArgListIter  iter(alist);
  235.          for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  236.                // don't display hidden arguments
  237.             if (cmdarg->syntax() & CmdArg::isHIDDEN)  continue;
  238.             if (!positionals  &&  (cmdarg->syntax() & CmdArg::isPOS))  continue;
  239.             if (positionals  &&  !(cmdarg->syntax() & CmdArg::isPOS))  continue;
  240.  
  241. #ifdef vms_style
  242.             if ( !options++ )   os << "Qualifiers/Parameters:\n" ;
  243. #else
  244.             if ( !options++ )   os << "Options/Arguments:\n" ;
  245. #endif
  246.             if (! fmt_arg(cmdarg, buf, sizeof(buf), syntax, TERSE_USAGE)) {
  247.                continue;
  248.             }
  249.             const char * description = cmdarg->description();
  250.             if ((description == NULL) || (! *description))  continue;
  251.             strindent(os, cols, 8, buf, (longest + 2), description);
  252.          } //for each cmdarg
  253.       } //for each arg-list
  254.    } //for each parm-type
  255. }
  256.  
  257. //-------
  258. // ^FUNCTION: CmdLine::usage - print command-usage
  259. //
  260. // ^SYNOPSIS:
  261. //    void CmdLine::usage(os, usage_level);
  262. //
  263. // ^PARAMETERS:
  264. //    ostream & os;
  265. //    -- where to print.
  266. //
  267. //    CmdLine::CmdUsageLevel  usage_level;
  268. //    -- verboseness to use.
  269. //
  270. // ^DESCRIPTION:
  271. //    Print the usage for the given CmdLine object on "os".
  272. //
  273. // ^REQUIREMENTS:
  274. //
  275. // ^SIDE-EFFECTS:
  276. //    Prints on "os".
  277. //
  278. // ^RETURN-VALUE:
  279. //    None.
  280. //
  281. // ^ALGORITHM:
  282. //    - get the usage level.
  283. //    - determine which syntax to use
  284. //    - get the max-columns for "os".
  285. //    - print synopsis if required.
  286. //    - print descriptions if required.
  287. //-^^----
  288. ostream &
  289. CmdLine::usage(ostream & os, CmdLine::CmdUsageLevel usage_level) const
  290. {
  291.    // get user-specified usage-level
  292.    //   (if status is zero this must be an explicit request so force verbose)
  293.    //
  294.    if (usage_level == DEFAULT_USAGE)  usage_level = get_usage_level();
  295.    if (usage_level == NO_USAGE)  return  os;
  296.  
  297.    // determine syntax to use
  298.    CmdLineSyntax  cmd_syntax = syntax() ;
  299.  
  300.    // get screen size (dont know how to do this yet)
  301.    int  max_cols = 79;
  302.  
  303.    // print command-line synopsis
  304.    unsigned  longest = print_synopsis(cmd_syntax, os, max_cols) ;
  305.    if (usage_level == TERSE_USAGE)  return  os;
  306.  
  307.    // now print argument descriptions
  308.    os << "\n" ;
  309.    print_descriptions(cmd_syntax, os, max_cols, longest) ;
  310.  
  311.    // now print the command-description if there is one
  312.    if (cmd_description && *cmd_description) {
  313.       os << "\nDescription:" << endl;
  314.       strindent(os, max_cols, 8, "", 0, cmd_description);
  315.    }
  316.  
  317.    return  os;
  318. }
  319.  
  320. ostream &
  321. CmdLine::usage(CmdLine::CmdUsageLevel usage_level) const {
  322.    return  usage(*cmd_err, usage_level);
  323. }
  324.  
  325.